package com.ydj.framework.utils;

import org.apache.commons.lang3.StringUtils;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

public class DateUtils {
    public final static long SECOND = 1000L;

    public final static long MINUTE = 60 * SECOND;

    public final static long HOUR = 60 * MINUTE;

    public final static long DAY = 24 * HOUR;

    /**
     * 获取昨天的时间范围
     *
     * @return return[0]: 昨天的00:00:00.000，昨天的23:59:59.999
     */
    public static long[] getYesterdayRange() {
        return getRange(-1, -1);
    }

    /**
     * 获取今天的时间范围
     *
     * @return return[0]: 今天的00:00:00.000，今天的23:59:59.999
     */
    public static long[] getTodayRange() {
        return getRange(0, 0);
    }

    /**
     * 获取前三十天
     *
     * @return
     */
    public static Date[] getThirtyRange() {
        long[] range = getRange(-29, 0);
        return new Date[]{new Date(range[0]), new Date(range[1])};
    }

    /**
     * 获取前七天
     *
     * @return
     */
    public static long[] getWeekRange() {
        return getRange(-7, -1);
    }

    /**
     * 获取距今时间范围
     *
     * @param start 开始时间（距今时间天数，返回当天 00:00:00:000 时间戳）
     * @param end   结束时间（距今时间天数，返回当天 23:59:59:000 时间戳）
     * @return 00:00:00:000 ---  23:59:59:000
     */
    public static long[] getRange(int start, int end) {
        Calendar startCalendar = Calendar.getInstance();
        startCalendar.add(Calendar.DAY_OF_MONTH, start);
        setMinTime(startCalendar);

        Calendar endCalendar = Calendar.getInstance();
        endCalendar.add(Calendar.DAY_OF_MONTH, end);
        setMaxTime(endCalendar);

        return new long[]{startCalendar.getTime().getTime(), endCalendar.getTime().getTime()};
    }

    /**
     * 获取两段时间天数差值
     */
    public static int getDateDifference(Date startDate, Date endDate) {
        long startTime = startDate.getTime() / DateUtils.DAY * DateUtils.DAY;
        long endTime = endDate.getTime() / DateUtils.DAY * DateUtils.DAY;
        return (int) ((endTime - startTime) / DateUtils.DAY);
    }

    /**
     * 获取两段时间天数差值（向上取整，1 天多一点算 2 天）
     */
    public static int getDateDifferenceCeil(Date startDate, Date endDate) {
        double startTime = startDate.getTime() * 1.0 / DateUtils.DAY * DateUtils.DAY;
        double endTime = endDate.getTime() * 1.0 / DateUtils.DAY * DateUtils.DAY;
        return (int) Math.ceil((endTime - startTime) / DateUtils.DAY);
    }

    /**
     * 计算两个值里相差了多少个月份
     */
    public static int getDataDiffMonth(Date start, Date end) {
        // 将Date对象转换为Calendar对象
        Calendar calendarStart = Calendar.getInstance();
        calendarStart.setTime(start);
        Calendar calendarEnd = Calendar.getInstance();
        calendarEnd.setTime(end);

        // 计算两个日期之间的月份差异
        int monthDiff = (calendarEnd.get(Calendar.YEAR) - calendarStart.get(Calendar.YEAR)) * 12 +
                calendarEnd.get(Calendar.MONTH) - calendarStart.get(Calendar.MONTH);

        // 输出相差的月数
        return monthDiff;
    }

    /**
     * 计算两个值里相差了多少分钟
     */
    public static long getDataDiffMinute(Date start, Date end) {
        long gap = end.getTime() - start.getTime();

        long minute = gap / MINUTE;
        if (gap % MINUTE != 0) {
            minute++;
        }
        return minute;
    }

    /**
     * 获取指定日期所在年份开始和结束的时间戳
     *
     * @return
     */
    public static long[] getYearRange(Integer year) {
        Calendar startCalendar = Calendar.getInstance();
        startCalendar.clear();
        startCalendar.set(Calendar.YEAR, year);


        Calendar endCalendar = Calendar.getInstance();
        endCalendar.clear();
        endCalendar.set(Calendar.YEAR, year);
        endCalendar.roll(Calendar.DAY_OF_YEAR, -1);
        setMaxTime(endCalendar);

        return new long[]{startCalendar.getTime().getTime(), endCalendar.getTime().getTime()};
    }


    /**
     * 获取近N个月开始和结束时间
     *
     * @param time N值
     * @return
     */
    public static long[] getBeforeMonthRange(Integer time) {
        Calendar startCalendar = Calendar.getInstance();
        int month = startCalendar.get(Calendar.MONTH);
        startCalendar.set(Calendar.MONTH, month - time);
        startCalendar.set(Calendar.DAY_OF_MONTH, 1);
        setMinTime(startCalendar);

        Calendar endCalendar = Calendar.getInstance();
        endCalendar.set(Calendar.MONTH, month - time);
        endCalendar.set(Calendar.DAY_OF_MONTH, endCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        setMaxTime(endCalendar);

        return new long[]{startCalendar.getTime().getTime(), endCalendar.getTime().getTime()};
    }

    /**
     * 获取指定日期所在开始时间戳
     *
     * @param date
     * @return
     */
    public static long getStartDay(Date date) {
        return getDayRange(date)[0];
    }

    /**
     * 获取指定日期所在开始和结束的时间戳
     *
     * @param date
     * @return
     */
    public static long[] getDayRange(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return getDayRange(c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH));
    }

    /**
     * 获取指定日期所在开始和结束的时间戳
     *
     * @return
     */
    public static long[] getDayRange(Integer year, Integer month, Integer day) {
        //0-11 对应1-12月
        Calendar startCalendar = Calendar.getInstance();
        startCalendar.clear();
        startCalendar.set(Calendar.YEAR, year);
        startCalendar.set(Calendar.MONTH, month);
        startCalendar.set(Calendar.DAY_OF_MONTH, day);


        Calendar endCalendar = Calendar.getInstance();
        endCalendar.clear();
        endCalendar.set(Calendar.YEAR, year);
        endCalendar.set(Calendar.MONTH, month);
        endCalendar.set(Calendar.DAY_OF_MONTH, day);
        setMaxTime(endCalendar);

        return new long[]{startCalendar.getTime().getTime(), endCalendar.getTime().getTime()};
    }

    /**
     * 获取指定日期所在月份开始和结束的时间戳
     *
     * @param date
     * @return
     */
    public static long[] getMonthRange(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return getMonthRange(c.get(Calendar.YEAR), c.get(Calendar.MONTH));
    }

    /**
     * 获取指定日期所在月份开始和结束的时间戳
     *
     * @return
     */
    public static long[] getMonthRange(Integer year, Integer month) {
        //0-11 对应1-12月
        Calendar startCalendar = Calendar.getInstance();
        startCalendar.clear();
        startCalendar.set(Calendar.YEAR, year);
        startCalendar.set(Calendar.MONTH, month);


        Calendar endCalendar = Calendar.getInstance();
        endCalendar.clear();
        endCalendar.set(Calendar.YEAR, year);
        endCalendar.set(Calendar.MONTH, month);
        endCalendar.roll(Calendar.DAY_OF_MONTH, -1);
        setMaxTime(endCalendar);

        return new long[]{startCalendar.getTime().getTime(), endCalendar.getTime().getTime()};
    }

    public static long startMonth(Date date) {
        return getMonthRange(date)[0];
    }

    public static long startWeek(Date date) {
        // 使用Calendar类进行时间的计算
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        setMinTime(cal);
        // 获得当前日期是一个星期的第几天
        // 判断要计算的日期是否是周日，如果是则减一天计算周六的，否则会计算到下一周去。
        // dayWeek值（1、2、3...）对应周日，周一，周二...
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
        if (dayWeek == 1) {
            dayWeek = 7;
        } else {
            dayWeek -= 1;
        }
        // 计算本周开始的时间
        cal.add(Calendar.DAY_OF_MONTH, 1 - dayWeek);
        return cal.getTime().getTime();

    }

    /**
     * 在时间上添加一段时间
     *
     * @param payTime 需要增加时间
     * @param type    calendar类型:天，月，年
     * @param num     数量
     * @return 结果时间
     */
    public static Date getAddTime(Date payTime, final int type, int num) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(payTime);
        cal.add(type, num);
        return cal.getTime();
    }

    public static Boolean isFirstDayOfMonth() {
        Calendar cal = Calendar.getInstance();
        return cal.get(Calendar.DAY_OF_MONTH) == 1;
    }

    private static void setMinTime(Calendar calendar) {
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
    }

    private static void setMaxTime(Calendar calendar) {
        calendar.set(Calendar.HOUR_OF_DAY, calendar.getActualMaximum(Calendar.HOUR_OF_DAY));
        calendar.set(Calendar.MINUTE, calendar.getActualMaximum(Calendar.MINUTE));
        calendar.set(Calendar.SECOND, calendar.getActualMaximum(Calendar.SECOND));
        calendar.set(Calendar.MILLISECOND, 0);
    }

    public static Date strToUtilDate(String strDate, String dateFormat) {
        SimpleDateFormat sf = new SimpleDateFormat(dateFormat);
        Date date = null;
        try {
            date = sf.parse(strDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    public static Integer dateToSecond(Date date) {
        if (date == null) {
            return null;
        }
        return (int) (date.getTime() / 1000);
    }

    public static String dateToSecond(Long second) {
        if (second == null) {
            return "";
        }
        return String.valueOf(second / 1000);
    }

    public static Date secondToDate(Long second) {
        if (second == null) {
            return null;
        }
        return new Date(second * 1000);
    }

    public static String secondToDateString(Long second) {
        if (second == null) {
            return null;
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date(second * 1000));
    }

    public static String msToDateString(Long ms) {
        if (ms == null) {
            return null;
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date(ms));
    }

    /**
     * Date -> String
     *
     * @param date
     * @return
     */
    public static String dateToString(Date date) {
        if (date == null) {
            return "";
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
    }

    public static String dateToFileNameString(Date date) {
        if (date == null) {
            return "";
        }
        return new SimpleDateFormat("yyyyMMdd-HHmmss").format(date);
    }


    /**
     * String -> Date
     *
     * @param dateStr
     * @return
     */
    public static Date stringToDate(String dateStr) throws ParseException {
        if (StringUtils.isBlank(dateStr)) {
            return null;
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr);
    }

    public static Date stringToDateWithoutException(String dateStr) {
        if (StringUtils.isBlank(dateStr)) {
            return null;
        }
        try {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr);
        } catch (ParseException e) {
            return null;
        }
    }

    public static int compareDate(String dateStr1, String dateStr2) {
        long date1;
        try {
            date1 = stringToDate(dateStr1).getTime();
        } catch (ParseException e) {
            date1 = 0;
        }
        long date2;
        try {
            date2 = stringToDate(dateStr2).getTime();
        } catch (ParseException e) {
            date2 = 0;
        }
        return Long.compare(date1, date2);
    }

    public static Integer getYearAndMonth(Date date) {
        String format = new SimpleDateFormat("yyyyMM").format(date);
        return Integer.parseInt(format);
    }


    public static String toStringDay(Date date) {
        if (date == null) {
            return "";
        }
        return new SimpleDateFormat("yyyy-MM-dd").format(date);
    }

    public static String toStringSecond(Date date) {
        if (date == null) {
            return "";
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
    }

    public static String toStringMonth(Date date) {
        if (date == null) {
            return "";
        }
        return new SimpleDateFormat("MM-dd").format(date);
    }

    public static String getTimeString(Date date) {
        if (date == null) {
            return "";
        }
        return new SimpleDateFormat("HH:mm:ss").format(date);
    }

    /***
     * convert Date to cron ,eg. "0 06 10 15 1 ? 2014"
     * @param date : 时间点
     * @return
     */
    public static String getCron(Date date) {
        String dateFormat = "ss mm HH dd MM ? yyyy";
        return formatDateByPattern(date, dateFormat);
    }

    /***
     *
     * @param date
     * @param dateFormat : e.g:yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static String formatDateByPattern(Date date, String dateFormat) {
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        String formatTimeStr = null;
        if (date != null) {
            formatTimeStr = sdf.format(date);
        }
        return formatTimeStr;
    }

    /**
     * 判断输入的时间是否在今天
     *
     * @param time 时间
     * @return 结果
     */
    public static boolean theTimeIsInToday(Date time) {
        long[] array = getTodayRange();
        return time.getTime() >= array[0] && time.getTime() <= array[1];
    }

    /**
     * 获取输入时间距离当前时间的秒数 (time > 当前，否则返回10s)
     *
     * @param time 时间
     * @return 时间
     */
    public static int getSecondsToCurrentTime(Date time) {
        int seconds = (int) ((time.getTime() - System.currentTimeMillis()) / SECOND);
        return seconds > 0 ? seconds : 10;
    }

    /**
     * 获取前七天的日期
     *
     * @return
     */
    public static String[] getBeforeSevenDay() {
        String[] arr = new String[7];
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar c = null;
        for (int i = 0; i < 7; i++) {
            c = Calendar.getInstance();
            c.add(Calendar.DAY_OF_MONTH, -i);
            arr[6 - i] = sdf.format(c.getTime());

        }
        return arr;
    }

    // 获取本周的开始时间
    public static Date getBeginDayOfWeek() {
        Date date = new Date();
        if (date == null) {
            return null;
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int dayofweek = cal.get(Calendar.DAY_OF_WEEK);
        if (dayofweek == 1) {
            dayofweek += 7;
        }
        cal.add(Calendar.DATE, 2 - dayofweek);
        return getDayStartTime(cal.getTime());
    }

    // 获取本周的结束时间
    public static Date getEndDayOfWeek() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getBeginDayOfWeek());
        cal.add(Calendar.DAY_OF_WEEK, 6);
        Date weekEndSta = cal.getTime();
        return getDayEndTime(weekEndSta);
    }

    // 获取本月的开始时间
    public static Date getBeginDayOfMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 1, 1);
        return getDayStartTime(calendar.getTime());
    }

    // 获取本月的结束时间
    public static Date getEndDayOfMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 1, 1);
        int day = calendar.getActualMaximum(5);
        calendar.set(getNowYear(), getNowMonth() - 1, day);
        return getDayEndTime(calendar.getTime());
    }

    // 获取某个日期的开始时间
    public static Timestamp getDayStartTime(Date d) {
        Calendar calendar = Calendar.getInstance();
        if (null != d) {
            calendar.setTime(d);
        }
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0,
                0, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    // 获取某个日期的结束时间
    public static Timestamp getDayEndTime(Date d) {
        Calendar calendar = Calendar.getInstance();
        if (null != d) {
            calendar.setTime(d);
        }
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 23,
                59, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return new Timestamp(calendar.getTimeInMillis());
    }

    // 获取今年是哪一年
    public static Integer getNowYear() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return Integer.valueOf(gc.get(1));
    }

    // 获取本月是哪一月
    public static int getNowMonth() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return gc.get(2) + 1;
    }

    // 获取当前日期在今年的第几周
    public static Integer getWeekOnYear(Date date) {
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return gc.get(3);
    }

    // 获取当期日期的前一天,昨天
    public static Date getThisDayYesterday(Date date) {
        Calendar ca = Calendar.getInstance();
        ca.setTime(date);
        ca.add(Calendar.DATE, -1);
        return ca.getTime();
    }

    // 获取当前的年月日字符串
    public static String getCurYearMonthDay() {
        return new SimpleDateFormat("yyyyMMdd").format(new Date());
    }

    public static void main(String[] args) throws ParseException {
        System.out.println(getDateDifferenceCeil(stringToDate("2021-01-20 13:51:00"), new Date()));
        System.out.println(toStringDay(getThisDayYesterday(new Date())));
    }
}